package com.qyer.search.model.lastminute;

import static com.qyer.commons.utils.CommonUtils.cast2Int;
import static com.qyer.commons.utils.CommonUtils.cast2String;
import static com.qyer.search.model.QyerPlace.buildCity;
import static com.qyer.search.model.QyerPlace.buildCountry;
import static com.qyer.search.model.lastminute.Tag.buildTag;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.*;
import com.qyer.search.Constants;
import com.qyer.search.cache.mutable.MutableCaches;
import com.qyer.search.enums.SKUChannel;
import com.qyer.search.enums.TagType;
import com.qyer.search.filter.AbstractFilter;
import com.qyer.search.filter.AbstractValidator;
import com.qyer.search.model.Channel;
import com.qyer.search.model.City;
import com.qyer.search.model.Country;
import com.qyer.search.model.SearchParameter;
import com.qyer.search.model.SearchParameterOrigin;
import com.qyer.search.model.SetOutPlace;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Created by tangzheng on 16/3/29.
 */
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY)
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(Include.NON_NULL)
public class BasicSKU extends SKU {

  @JsonProperty(FIELD_OUT_ID)
  private int id;
  @JsonProperty(FIELD_OUT_TYPE1)
  private int type1;
  @JsonProperty(FIELD_OUT_TYPE2)
  private int type2;

  @JsonProperty(FIELD_OUT_BASIC_COUNTRIES)
  private List<Integer> destinationCountries;
  @JsonProperty(FIELD_OUT_BASIC_CITIES)
  private List<Integer> destinationCities;
  @JsonProperty(FIELD_OUT_BASIC_CONTINENT)
  private List<Integer> destinationContinents;

  public static BasicSKU build() {
    return new BasicSKU();
  }

  public static BasicSKU build(SearchParameter sp, Map<String, Object> dataMap) {
    if (MapUtils.isEmpty(dataMap)) {
      return null;
    }
    int id = cast2Int(dataMap.get(FIELD_ID));
    AbstractValidator validator = MutableCaches.getInstance().SKU_AVAILABILITY_VALIDATOR
      .getCacheContent();
    if (!validator.isValid(sp, id)) {
      return null;
    }
    BasicSKU sku = build().id(id)
                         .type1(cast2Int(dataMap.get(FIELD_TYPE1)))
                         .type2(cast2Int(dataMap.get(FIELD_TYPE2)));

    List<Map<String, Object>> listedData = (List<Map<String, Object>>) dataMap.get(FIELD_TAGS);
    Tag tag;
    if (CollectionUtils.isNotEmpty(listedData)) {
      for (Map<String, Object> map : listedData) {
        tag = buildTag(map);
        if (tag == null) {
          continue;
        }

        if(tag.getTagType() == TagType.CITY){
          sku.addCityId(tag.getTagName());
        }else if(tag.getTagType() == TagType.COUNTRY) {
          sku.addCountryId(tag.getTagName());
        } else if(tag.getTagType() == TagType.CONTINENT) {
          sku.addContinentId(tag.getTagName());
        }
      }
    }
    return sku;
  }

  public static BasicSKU build(SearchParameterOrigin sp, Map<String, Object> dataMap) {
    if (MapUtils.isEmpty(dataMap)) {
      return null;
    }
    int id = cast2Int(dataMap.get(FIELD_ID));
    AbstractValidator validator = MutableCaches.getInstance().SKU_AVAILABILITY_VALIDATOR
      .getCacheContent();
    if (!validator.isValid(sp, id)) {
      return null;
    }
    BasicSKU sku = build().id(id)
                         .type1(cast2Int(dataMap.get(FIELD_TYPE1)))
                         .type2(cast2Int(dataMap.get(FIELD_TYPE2)));
    List<Map<String, Object>> listedData = (List<Map<String, Object>>) dataMap.get(FIELD_TAGS);
    Tag tag;
    if (CollectionUtils.isNotEmpty(listedData)) {
      for (Map<String, Object> map : listedData) {
        tag = buildTag(map);
        if (tag == null) {
          continue;
        }
        if(tag.getTagType() == TagType.CITY){
          sku.addCityId(tag.getTagName());
        }else if(tag.getTagType() == TagType.COUNTRY) {
          sku.addCountryId(tag.getTagName());
        } else if(tag.getTagType() == TagType.CONTINENT) {
          sku.addContinentId(tag.getTagName());
        }
      }
    }
    return sku;
  }

  public static BasicSKU build(SearchParameterOrigin sp, Map<String, Object> dataMap,
                               Map<Integer,Map<Integer,Integer>> placeSearchCensus,
                               Map<Integer,Map<Integer,Integer>> typeSearchCensus) {
    if (MapUtils.isEmpty(dataMap)) {
      return null;
    }
    int id = cast2Int(dataMap.get(FIELD_ID));
    AbstractValidator validator = MutableCaches.getInstance().SKU_AVAILABILITY_VALIDATOR
      .getCacheContent();
    if (!validator.isValid(sp, id)) {
      return null;
    }
    int t1 = cast2Int(dataMap.get(FIELD_TYPE1));
    int t2 = cast2Int(dataMap.get(FIELD_TYPE2));
    BasicSKU sku = build().id(id)
                          .type1(t1)
                          .type2(t2);
    if(t1 != 0) {
      if (typeSearchCensus.containsKey(t1)) {
        int tmp = typeSearchCensus.get(t1).get(-1) + 1;
        typeSearchCensus.get(t1).put(-1, tmp);
      }else {
        Map<Integer, Integer> map = new HashMap<>();
        map.put(-1, 1);
        typeSearchCensus.put(t1, map);
      }
    }
    if(t2 != 0) {
      if (typeSearchCensus.containsKey(t2)) {
        int tmp = typeSearchCensus.get(t2).get(-1) + 1;
        typeSearchCensus.get(t2).put(-1, tmp);
      }else {
        Map<Integer, Integer> map = new HashMap<>();
        map.put(-1, 1);
        typeSearchCensus.put(t2, map);
      }
    }
    List<Map<String, Object>> listedData = (List<Map<String, Object>>) dataMap.get(FIELD_TAGS);
    Tag tag;
    if (CollectionUtils.isNotEmpty(listedData)) {
      for (Map<String, Object> map : listedData) {
        tag = buildTag(map);
        if (tag == null) {
          continue;
        }
        if(tag.getTagType() == TagType.CITY){
          sku.addCityId(tag.getTagName());
          int cityId = BasicSKU.getCityId(tag.getTagName());
          if(cityId != -1){
            if(placeSearchCensus.containsKey(cityId)){
              int tmp = placeSearchCensus.get(cityId).get(-1) + 1;
              placeSearchCensus.get(cityId).put(-1, tmp);
            }else {
              Map<Integer, Integer> mapTmp = new HashMap<>();
              mapTmp.put(-1, 1);
              placeSearchCensus.put(cityId, mapTmp);
            }
          }
        }else if(tag.getTagType() == TagType.COUNTRY) {
          sku.addCountryId(tag.getTagName());
        } else if(tag.getTagType() == TagType.CONTINENT) {
          sku.addContinentId(tag.getTagName());
        }
      }
    }
    return sku;
  }

  public static BasicSKU build(SearchParameterOrigin sp, Map<String, Object> dataMap, List<AbstractFilter> filters,
                               Map<Integer,Map<Integer,Integer>> placeSearchCensus,
                               Map<Integer,Map<Integer,Integer>> typeSearchCensus) {
    if (MapUtils.isEmpty(dataMap)) {
      return null;
    }
    int id = cast2Int(dataMap.get(FIELD_ID));
    AbstractValidator validator = MutableCaches.getInstance().SKU_AVAILABILITY_VALIDATOR
      .getCacheContent();
    if (!validator.isValid(sp, id)) {
      return null;
    }
    for(int i = 0; i < filters.size(); i++){
      if(!filters.get(i).isValid(dataMap, sp))
        return null;
    }
    int t1 = cast2Int(dataMap.get(FIELD_TYPE1));
    int t2 = cast2Int(dataMap.get(FIELD_TYPE2));
    BasicSKU sku = build().id(id)
                          .type1(t1)
                          .type2(t2);
    if(t1 != 0) {
      if (typeSearchCensus.containsKey(t1)) {
        int tmp = typeSearchCensus.get(t1).get(-1) + 1;
        typeSearchCensus.get(t1).put(-1, tmp);
      }else {
        Map<Integer, Integer> map = new HashMap<>();
        map.put(-1, 1);
        typeSearchCensus.put(t1, map);
      }
    }
    if(t2 != 0) {
      if (typeSearchCensus.containsKey(t2)) {
        int tmp = typeSearchCensus.get(t2).get(-1) + 1;
        typeSearchCensus.get(t2).put(-1, tmp);
      }else {
        Map<Integer, Integer> map = new HashMap<>();
        map.put(-1, 1);
        typeSearchCensus.put(t2, map);
      }
    }
    List<Map<String, Object>> listedData = (List<Map<String, Object>>) dataMap.get(FIELD_TAGS);
    Tag tag;
    //boolean isHongKong = false;
    //boolean isMaco = false;
    if (CollectionUtils.isNotEmpty(listedData)) {
      for (Map<String, Object> map : listedData) {
        tag = buildTag(map);
        if (tag == null) {
          continue;
        }
        String tagName = tag.getTagName();
        //特殊城市
        /*if("香港".equals(tagName)){
          isHongKong = true;
          continue;
        }
        if("澳门".equals(tagName)){
          isMaco = true;
          continue;
        }*/
        if(tag.getTagType() == TagType.CITY){
          sku.addCityId(tagName);

          int cityId = BasicSKU.getCityId(tag.getTagName());
          if(cityId != -1){
            if(placeSearchCensus.containsKey(cityId)){
              int tmp = placeSearchCensus.get(cityId).get(-1) + 1;
              placeSearchCensus.get(cityId).put(-1, tmp);
            }else {
              Map<Integer, Integer> mapTmp = new HashMap<>();
              mapTmp.put(-1, 1);
              placeSearchCensus.put(cityId, mapTmp);
            }
          }
        }else if(tag.getTagType() == TagType.COUNTRY) {
          sku.addCountryId(tagName);
        } else if(tag.getTagType() == TagType.CONTINENT) {
          sku.addContinentId(tagName);
        }
      }
    }

    /*
    if(CollectionUtils.isEmpty(sku.getDestinationCountries())) {
      if (isHongKong) {
        sku.addCityId("香港");
      }
      if (isMaco) {
        sku.addCityId("澳门");
      }
    }*/
    return sku;
  }

  public static BasicSKU build(SearchParameterOrigin sp, Map<String, Object> dataMap, List<AbstractFilter> filters) {
    if (MapUtils.isEmpty(dataMap)) {
      return null;
    }
    int id = cast2Int(dataMap.get(FIELD_ID));
    AbstractValidator validator = MutableCaches.getInstance().SKU_AVAILABILITY_VALIDATOR
      .getCacheContent();
    if (!validator.isValid(sp, id)) {
      return null;
    }
    for(int i = 0; i < filters.size(); i++){
      if(!filters.get(i).isValid(dataMap, sp))
        return null;
    }
    BasicSKU sku = build().id(id)
                          .type1(cast2Int(dataMap.get(FIELD_TYPE1)))
                          .type2(cast2Int(dataMap.get(FIELD_TYPE2)));
    List<Map<String, Object>> listedData = (List<Map<String, Object>>) dataMap.get(FIELD_TAGS);
    Tag tag;
    //boolean isHongKong = false;
    //boolean isMaco = false;
    if (CollectionUtils.isNotEmpty(listedData)) {
      for (Map<String, Object> map : listedData) {
        tag = buildTag(map);
        if (tag == null) {
          continue;
        }
        String tagName = tag.getTagName();
        //特殊城市
        /*if("香港".equals(tagName)){
          isHongKong = true;
          continue;
        }
        if("澳门".equals(tagName)){
          isMaco = true;
          continue;
        }*/
        if(tag.getTagType() == TagType.CITY){
          sku.addCityId(tagName);
        }else if(tag.getTagType() == TagType.COUNTRY) {
          sku.addCountryId(tagName);
        } else if(tag.getTagType() == TagType.CONTINENT) {
          sku.addContinentId(tagName);
        }
      }
    }

    /*
    if(CollectionUtils.isEmpty(sku.getDestinationCountries())) {
      if (isHongKong) {
        sku.addCityId("香港");
      }
      if (isMaco) {
        sku.addCityId("澳门");
      }
    }*/
    return sku;
  }

  public BasicSKU id(int id) {
    setId(id);
    return this;
  }

  public BasicSKU type1(int type1) {
    setType1(type1);
    return this;
  }

  public BasicSKU type2(int type2) {
    setType2(type2);
    return this;
  }


  public BasicSKU() {
  }

  public BasicSKU(int id) {
    this.id = id;
  }

  public int getId() {
    return id;
  }

  public void setId(int id) {
    this.id = id;
  }

  public int getType1() {
    return type1;
  }

  public void setType1(int type1) {
    this.type1 = type1;
  }

  public int getType2() {
    return type2;
  }

  public void setType2(int type2) {
    this.type2 = type2;
  }

  public List<Integer> getDestinationCountries() {
    return destinationCountries;
  }

  public void setDestinationCountries(List<Integer> destinationCountries) {
    this.destinationCountries = destinationCountries;
  }

  public void addCountryId(String countryName){
    if(StringUtils.isBlank(countryName))
      return;

    if(MutableCaches.getInstance().COUNTRIES.getCacheContent().containsKey(countryName)) {
      if(CollectionUtils.isEmpty(this.destinationCountries))
        this.destinationCountries = new ArrayList<>(2);
      this.destinationCountries
        .add(MutableCaches.getInstance().COUNTRIES.getCacheContent().get(countryName));
    }
  }

  public List<Integer> getDestinationCities() {
    return destinationCities;
  }

  public void setDestinationCities(List<Integer> destinationCities) {
    this.destinationCities = destinationCities;
  }

  public void addCityId(String cityName){
    if(StringUtils.isBlank(cityName))
      return;
    if(MutableCaches.getInstance().CITIES.getCacheContent().containsKey(cityName)) {
      if (CollectionUtils.isEmpty(this.destinationCities))
        this.destinationCities = new ArrayList<>(3);
      this.destinationCities.add(MutableCaches.getInstance().CITIES.getCacheContent().get(cityName));
    }
  }

  public static int getCityId(String cityName){
    if(StringUtils.isBlank(cityName))
      return -1;
    if(MutableCaches.getInstance().CITIES.getCacheContent().containsKey(cityName)){
      return MutableCaches.getInstance().CITIES.getCacheContent().get(cityName);
    }
    return -1;
  }

  public List<Integer> getDestinationContinents() {
    return destinationContinents;
  }

  public void setDestinationContinents(List<Integer> destinationContinents) {
    this.destinationContinents = destinationContinents;
  }

  public void addContinentId(String continentName){
    if(StringUtils.isBlank(continentName))
      return;
    if(Constants.CONTINENT_MAP.containsKey(continentName)) {
      if (CollectionUtils.isEmpty(this.destinationContinents))
        this.destinationContinents = new ArrayList<>(1);
      this.destinationContinents.add(Constants.CONTINENT_MAP.get(continentName));
    }
  }

  @Override public String toString() {
    return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).append("id", id)
                                                                      .append("type1", type1)
                                                                      .append("type2", type2)
                                                                      .append("des_countries", destinationCountries)
                                                                      .append("des_cities", destinationCities)
                                                                      .append("des_continent",
                                                                              destinationContinents)
                                                                      .toString();
  }

  public static String unknownPositionSKU(int skuId) {
    return "SKU(" + skuId + ")-UnknownPosition";
  }

  public static String naSKU(int skuId) {
    return "SKU(" + skuId + ")-NotAvailable";
  }
}

